from app.config import config

config.set_langsmith_env()

import asyncio  # 用于异步编程。
import uuid

from app.agent.toolcall import ToolCallAgent
from app.exception import TokenLimitExceeded
from app.logger import logger
from app.mcp.client import get_mcp_tools
from app.tool.tavily_search import tavily_search
from app.tool.file.read import ReadFile


# 协程是异步编程的基本单位，由 async def 定义的函数。
async def main():
    choose_tool = input("默认不使用工具，输入‘1’启用 MCP Servers，输入‘2’启用 Function Calling: ").strip()
    tools = []
    if choose_tool == "1":
        tools = await get_mcp_tools()
    elif choose_tool == "2":
        tools = [ReadFile(), tavily_search]

    agent = ToolCallAgent(
        name="Test tool call agent",
        tools=tools,
        thread_id=uuid.uuid4()
    )

    try:
        while True:
            user_input = input("发送消息（输入‘quit’退出，输入‘new'开启新对话）: ").strip()
            if user_input.lower() == "quit":
                logger.info("Quited by user.")
                break

            if not user_input:
                logger.warning("Empty user input provided.")
                continue

            if user_input.lower() == "new":
                logger.info("Starting a new conversation by user.")
                agent.thread_id = uuid.uuid4()
                continue

            logger.info("Processing your request...")
            agent.input_msg_of_this_round = [{"role": "user", "content": user_input}]
            try:
                # 切换到 agent.run 协程
                # 当使用 await 调用一个异步函数时，它不会立即执行，而是返回一个协程对象;
                # 同时会暂停 main 协程的执行，直到 Manus.create() 完成并返回代理实例；
                # await 关键字确实会让当前协程暂停执行，但这种“暂停”是协作式的，并不会阻塞整个程序或事件循环（Event Loop）。
                res = await agent.run()
                res[-1]["messages"][-1].pretty_print()
                logger.info("Request processing completed.")
            except TokenLimitExceeded as e:
                logger.warning(f"Token limit exceeded: {str(e)}")
    except KeyboardInterrupt:
        logger.warning("Keyboard interrupted.")


if __name__ == "__main__":
    # 运行异步主函数：会创建一个新的事件循环，运行 main 协程，并在 main 协程完成后关闭事件循环。
    asyncio.run(main())
